package com.zx.designpattern.utils.interfaceforall;

import java.util.HashMap;


/**
 * Created by zhoux on 2018/2/1.
 * 注释：万能接口管理实现类
 */

public class FunctionManager extends FunctionManagerInterface {
    private static volatile FunctionManager mFunctionManager = null;

    private HashMap<String, FunctionNoParamNoResult> mFunctionNoParamNoResult;
    private HashMap<String, FunctionWithParamOnly> mFunctionWithParamOnly;
    private HashMap<String, FunctionWithResultOnly> mFunctionWithResultOnly;
    private HashMap<String, FunctionWithParamAndResult> mFunctionWithParamAndResult;

    private FunctionManager() {
        mFunctionNoParamNoResult = new HashMap();
        mFunctionWithParamAndResult = new HashMap();
        mFunctionWithParamOnly = new HashMap();
        mFunctionWithResultOnly = new HashMap();
    }

    /**
     * DCL方式的单例模式
     *
     * @return
     */
    public static FunctionManager getInstance() {
        if (mFunctionManager == null) {
            synchronized (FunctionManager.class) {
                if (mFunctionManager == null) {
                    mFunctionManager = new FunctionManager();
                }
            }
        }
        return mFunctionManager;
    }

    /**
     * name前缀，用于区分方法,这样使用add方法增加接口的时候，使用类的全名就行，不要考虑名称重复问题
     */
    private interface NAME_PRE {
        String npnr_ = "npnr_";//无参数，无返回值
        String wpo_ = "wpo_";//有参数，无返回值
        String wro_ = "wro_";//无参数，有返回值
        String wpar_ = "wpar_";//有参数，有返回值
    }

    public FunctionManager addFunctionNoParamNoResult(FunctionNoParamNoResult mFunction) {
        if (mFunction == null) {
            return this;
        }
        if (mFunction.mFunctionName == null) {
            return this;
        }
        String name = NAME_PRE.npnr_ + mFunction.mFunctionName;
        if (mFunctionNoParamNoResult.get(name) != null) {
            return this;
        }

        mFunctionNoParamNoResult.put(name, mFunction);
        return this;
    }


    public FunctionManager addFunctionWithParamOnly(FunctionWithParamOnly mFunction) {
        if (mFunction == null) {
            return this;
        }
        if (mFunction.mFunctionName == null) {
            return this;
        }
        String name = NAME_PRE.wpo_ + mFunction.mFunctionName;
        if (mFunctionWithParamOnly.get(name) != null) {
            return this;
        }

        mFunctionWithParamOnly.put(name, mFunction);
        return this;
    }

    @Override
    public FunctionManager addFunctionWithResultOnly(FunctionWithResultOnly mFunction) {
        if (mFunction == null) {
            return this;
        }
        if (mFunction.mFunctionName == null) {
            return this;
        }
        String name = NAME_PRE.wro_ + mFunction.mFunctionName;
        if (mFunctionWithResultOnly.get(name) != null) {
            return this;
        }
        mFunctionWithResultOnly.put(name, mFunction);
        return this;
    }


    public FunctionManager addFunctionWithParamAndResult(FunctionWithParamAndResult mFunction) {
        if (mFunction == null) {
            return this;
        }
        if (mFunction.mFunctionName == null) {
            return this;
        }
        String name = NAME_PRE.wpar_ + mFunction.mFunctionName;
        if (mFunctionWithParamAndResult.get(name) != null) {
            return this;
        }
        mFunctionWithParamAndResult.put(name, mFunction);
        return this;
    }

    public void invokeFunctionNoParamNoResult(String functionName) {
        if (functionName == null) {
            return;
        }
        String name = NAME_PRE.npnr_ + functionName;
        FunctionNoParamNoResult mFunction = mFunctionNoParamNoResult.get(name);
        if (mFunction == null) {
            throw new FunctionException("找不到接口！ 请保证：你已经用<" + functionName + ">这个方法名增加了接口！");
        }
        mFunction.function();
        return;
    }

    public <Param> void invokeFunctionWithParamOnly(String functionName, Param param) {
        if (functionName == null) {
            return;
        }
        String name = NAME_PRE.wpo_ + functionName;
        FunctionWithParamOnly mFunction = mFunctionWithParamOnly.get(name);
        if (mFunction == null) {
            throw new FunctionException("找不到接口！ 请保证：你已经用<" + functionName + ">这个方法名增加了接口！");
        }
        mFunction.function(param);
        return;
    }

    @Override
    public <Result> Result invokeFunctionWithResultOnly(String functionName, Class<Result> c) {
        if (functionName == null) {
            return null;
        }
        String name = NAME_PRE.wro_ + functionName;
        FunctionWithResultOnly mFunction = mFunctionWithResultOnly.get(name);
        if (mFunction == null) {
            throw new FunctionException("找不到接口！ 请保证：你已经用<" + functionName + ">这个方法名增加了接口！");
        }
        if (c != null) {
            return c.cast(mFunction.function());
        } else {
            return (Result) mFunction.function();
        }
    }

    public <Result, Param> Result invokeFunctionWithParamAndResult(String functionName, Class<Result> c, Param param) {
        if (functionName == null) {
            return null;
        }
        String name = NAME_PRE.wpar_ + functionName;
        FunctionWithParamAndResult mFunction = mFunctionWithParamAndResult.get(name);
        if (mFunction == null) {
            throw new FunctionException("找不到接口！ 请保证：你已经用<" + functionName + ">这个方法名增加了接口！");
        }
        if (c != null) {
            return c.cast(mFunction.function(param));
        } else {
            return (Result) mFunction.function(param);
        }
    }

    public void clear(String functionName) {
        if (functionName == null) {
            return;
        }
        String npnr_name = NAME_PRE.npnr_ + functionName;
        String wpo_name = NAME_PRE.wpo_ + functionName;
        String wro_name = NAME_PRE.wro_ + functionName;
        String wpar_name = NAME_PRE.wpar_ + functionName;
        if (mFunctionNoParamNoResult != null)
            mFunctionNoParamNoResult.remove(npnr_name);
        if (mFunctionWithParamOnly != null)
            mFunctionWithParamOnly.remove(wpo_name);
        if (mFunctionWithResultOnly != null)
            mFunctionWithResultOnly.remove(wro_name);
        if (mFunctionWithParamAndResult != null)
            mFunctionWithParamAndResult.remove(wpar_name);
    }
}
